package com.example.java_gobang.game;

import com.example.java_gobang.JavaGobangApplication;
import com.example.java_gobang.model.User;
import com.example.java_gobang.model.UserMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.UUID;

/**
 * @author hanzishuai
 * @date 2025/03/03 11:24
 * @Description 表示一个游戏房间
 */
@Slf4j
public class Room {
    private static final int MAX_ROW = 15;
    private static final int MAX_COL = 15;

    private String roomId;

    private User user1;
    private User user2;

    // 先手方的玩家ID
    private int whiteUser;

    // 表示棋盘，0 表示未落子，1 表示 user1 落子位置，2 表示user2 落子位置
    private int[][] board = new int[MAX_ROW][MAX_COL];

    private ObjectMapper objectMapper = new ObjectMapper();

    private OnlineUserManager onlineUserManager;

    private RoomManger roomManger;

    private UserMapper userMapper;

    // 处理落子请求
    public void putChess(String reqString) throws IOException {
        GameRequest request = objectMapper.readValue(reqString, GameRequest.class);
        GameResponse response = new GameResponse();
        // 判断当前落子是谁落的
        int chess = request.getUserId() == user1.getUserId() ? 1 : 2;
        int row = request.getRow();
        int col = request.getCol();
        if (board[row][col] != 0) {
            //这个位置已经有人落子了
            log.error("当前位置 (" + row + " , " + col + " ) 已经有子了");
            return;
        }

        board[row][col] = chess;

        // 打印棋盘信息，方便观察
        printBoard();


        // 判断胜负
        int winner = checkWinner(row, col, chess);

        // 返回响应的内容
        response.setMessage("putChess");
        response.setUserId(request.getUserId());
        response.setRow(row);
        response.setCol(col);
        response.setWinner(winner);

        // 给房间中的所有客户端，返回响应
        WebSocketSession session1 = onlineUserManager.getFromGameRoom(user1.getUserId());
        WebSocketSession session2 = onlineUserManager.getFromGameRoom(user2.getUserId());

        if (session1 == null) {
            // 玩家一下线，认为玩家二获胜
            response.setWinner(user2.getUserId());
            log.info("玩家1 掉线！");
        }
        if (session2 == null) {
            // 玩家二下线，认为玩家一获胜
            response.setWinner(user1.getUserId());
            log.info("玩家2 掉线！");
        }

        String respJson = objectMapper.writeValueAsString(response);
        if (session1 != null) {
            session1.sendMessage(new TextMessage(respJson));
        }
        if (session2 != null) {
            session2.sendMessage(new TextMessage(respJson));
        }

        // 如果胜负已分，此时销毁房间
        if (response.getWinner() != 0) {
            // 胜负已分
            log.info("游戏结束！房间即将销毁！roomId = " + roomId + "，获胜方：" + response.getWinner());
            // 更新获胜方和失败方的信息
            int winUserId = response.getWinner();
            int loseUserId = response.getWinner() == user1.getUserId() ? user2.getUserId() : user1.getUserId();
            userMapper.userWin(winUserId);
            userMapper.userLose(loseUserId);

            // 销毁房间
            roomManger.remove(roomId, user1.getUserId(), user2.getUserId());
        }

    }

    // 这个方法用来判断胜负
    private int checkWinner(int row, int col, int chess) {
        // 检查所有行
        for (int c = col - 4; c <= col; c++) {
            try {
                if (board[row][c] == chess && board[row][c + 1] == chess
                        && board[row][c + 2] == chess && board[row][c + 3] == chess
                        && board[row][c + 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }
        // 检查所有列
        for (int r = row-4; r <= row ; r++) {
            try {
                if (board[r][col] == chess && board[r + 1][col] == chess
                        && board[r + 2][col] == chess && board[r + 3][col] == chess
                        && board[r + 4][col] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        // 检查左对角线
        for (int r = row - 4, c = col - 4; r <= row && c <= col; r++, c++) {
            try {
                if (board[r][c] == chess && board[r + 1][c + 1] == chess
                        && board[r + 2][c + 2] == chess && board[r + 3][c + 3] == chess
                        && board[r + 4][c + 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }


        // 检查右对角线
        for (int r = row - 4, c = col + 4; r <= row && c >= col; r++, c--) {
            try {
                if (board[r][c] == chess && board[r + 1][c - 1] == chess
                        && board[r + 2][c - 2] == chess && board[r + 3][c - 3] == chess
                        && board[r + 4][c - 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }
        // 胜负未分
        return 0;


    }

    // 打印棋盘
    private void printBoard() {
        log.info("[打印棋盘信息]" + roomId);
        System.out.println("=================================");
        for (int i = 0; i < MAX_ROW; i++) {
            System.out.print("  ");
            for (int j = 0; j < MAX_COL; j++) {
                System.out.print(board[i][j] + " ");
            }
            System.out.println();
        }
        System.out.println("=================================");
    }

    public static void main(String[] args) {
        Room room = new Room();
        room.printBoard();
    }

    public int getWhiteUser() {
        return whiteUser;
    }

    public void setWhiteUser(int whiteUser) {
        this.whiteUser = whiteUser;
    }

    public String getRoomId() {
        return roomId;
    }

    public void setRoomId(String roomId) {
        this.roomId = roomId;
    }

    public User getUser1() {
        return user1;
    }

    public void setUser1(User user1) {
        this.user1 = user1;
    }

    public User getUser2() {
        return user2;
    }

    public void setUser2(User user2) {
        this.user2 = user2;
    }

    public Room() {
        roomId = UUID.randomUUID().toString();
        // 通过入口类中记录的 context 来手动管理 RoomManger 和 OnlineUserManager
        onlineUserManager = JavaGobangApplication.context.getBean(OnlineUserManager.class);
        roomManger = JavaGobangApplication.context.getBean(RoomManger.class);
        userMapper = JavaGobangApplication.context.getBean(UserMapper.class);
    }
}
